package io.kiki.stack.netty.processor;


import io.kiki.stack.netty.channelManager.Channel;
import io.kiki.stack.netty.channelManager.ChannelContext;
import io.kiki.stack.netty.command.Command;
import io.kiki.stack.netty.invoker.Future;
import io.kiki.stack.netty.util.InetSocketAddressUtil;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Executor;


@Slf4j
@Setter
@Getter
public class ResponseProcessor extends AbstractProcessor<Command> {


    public ResponseProcessor() {

    }

    public ResponseProcessor(Executor executor) {
        super(executor);
    }


    @Override
    public void doProcess(ChannelContext channelContext, Command command) {

        Channel channel = channelContext.getChannelHandlerContext().channel().attr(Channel.CHANNEL).get();
        Future future = channel.removeFuture(command.getId());
        ClassLoader oldClassLoader = null;
        try {
            if (future != null) {
                if (future.getAppClassLoader() != null) {
                    oldClassLoader = Thread.currentThread().getContextClassLoader();
                    Thread.currentThread().setContextClassLoader(future.getAppClassLoader());
                }
                future.putResponse(command);
                future.cancelTimeout();
                try {
                    future.executeInvokeCallback();
                } catch (Exception e) {
                    log.error("Exception caught when executing invoke callback, id={}", command.getId(), e);
                }
            } else {
                log.warn("Cannot find InvokeFuture, maybe already timeout, id={}, from={} ", command.getId(), InetSocketAddressUtil.parseRemoteAddress(channelContext.getChannelHandlerContext().channel()));
            }
        } finally {
            if (null != oldClassLoader) {
                Thread.currentThread().setContextClassLoader(oldClassLoader);
            }
        }

    }

}
